//importing javascipt core modules
Components.utils.import("resource://downloadextender/common.js");
Components.utils.import("resource://downloadextender/downloadextender.js");
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");

/**
 * downloadextender namespace.
 */
if ("undefined" == typeof(downloadextender)) {
  var downloadextender = {};
};

/**
 * Controls the browser overlay for the downloadextender extension.
 */
downloadextender.BrowserOverlay = {
    /*Observer service */
	_observerService : null,

	/**
	 * Initializes this object
	 */
    init: function() {
	  try {
	    this._observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
	    this._observerService.addObserver(this, "http-on-examine-response", false);
	    if (downloadextender.pref.firstrun == true) {
          let kToolBarID = "nav-bar";
          let kTBItemID = "downloadextender-toolbarbutton";
          let tbElem = document.getElementById(kToolBarID);
          let tbItemElem = document.getElementById(kTBItemID);
          if (tbElem && !tbItemElem) {
            let newSet = tbElem.currentSet + "," + kTBItemID;
            tbElem.setAttribute("currentset", newSet);
            tbElem.currentSet = newSet;
            document.persist(kToolBarID, "currentset");   
          }	
          downloadextender.pref.savefirstrun(downloadextender.pref.firstrun); 
        }
	  }
	  catch (e) { downloadextender.consoleService("init: "+e); }
	},
	
	/**
	 * Uninitializes this object
	 */
	 uninit : function() {
	   try  {
	     this._observerService.removeObserver(this, "http-on-examine-response");
	   }
	   catch (e) { downloadextender.consoleService("uninit: "+e); }
	 },

	/**
	 * Observes the registered notification topic(s)
	 */	 
	 observe : function(aSubject, aTopic, aData) {
	   try  {
	       if (downloadextender.pref.listen != false && aTopic == "http-on-examine-response")  {
		       aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
			  
			   //gets the responsecode from the http channel (e.g. 200)
               let _responseStatus = aSubject.responseStatus.toString();	  
			 
			   //makes only a succes http code can be used
			   if(_responseStatus.match(/200/)) {
			   
			   //gets the content-type 			   
			   let _contenttype  = aSubject.getResponseHeader("Content-Type");
			   
			   //gets filters from preferences
			   let filters = downloadextender.pref.filters;	
               let blacklist = downloadextender.pref.blacklist;				   
  
				 for(var i in filters) {
                   let filter = filters[i];				   
				   
					 //checks if content-type equals enabled filter
					 let verified;
					 if (new RegExp(filter["contenttype"]).exec(_contenttype) && filter["enabled"] == "true") { verified = "true"; }
					 else { verified = "false"; }
				     if  (verified == "true" || downloadextender.pref.detectall == true)  {
					 
                       //gets the size of file
			           let _length = "";
			           try { _length = aSubject.getResponseHeader("Content-Length");} catch(e) { }
			 
			           //gets URI
					   let uri = aSubject.URI.asciiSpec;	
					   
					   let forbiddenurlfound = false;
					   if (downloadextender.pref.blacklistenable == true) {
					     //check if URI is not in blacklist
					     for(var y in blacklist) {
						   let blacklistfilter = blacklist[y];							
					       if  (new RegExp(blacklistfilter["URL"]).exec(uri) && blacklistfilter["enabled"] == "true" )  {
						     forbiddenurlfound = true;							 
			               }
                         }
                       }					   
			   
			           if (forbiddenurlfound == false) {
			   
			             //gets filename from URI (e.g. http://test.be/icon_busy.gif?20121128 becomes icon_busy.gif)
					     let ioservice = downloadextender.ioservice();
					     myURI = ioservice.newURI(uri,null,null)
					     let _fileleaveString = myURI.QueryInterface(Ci.nsIURL).fileName;	
					   
					     //removes illegal characters from string
					     let _filename = _fileleaveString.replace(/[|&;$%@"<>()+,=:{}']/g, "");	
					   
                         //gets unique id for filename
                         let uuidgeneratornumber = downloadextender.uuidgenerator().generateUUID();	
					   
					     //add the unique id before the extension of the filename	
                         //also avoids long filenames					   
					     let stringindex = _filename.lastIndexOf(".")
					     if (stringindex > 0) {
					       //e.g. alex.jpg becomes alex
					       let _filenamefront = _filename.substring(0, stringindex)
						 
						   //avoids long file names
						   if (_filenamefront.length > 64) {
					         let _filenamefrontshort = _filenamefront.slice(0,64);
						     _filenamefront = _filenamefrontshort;
					       }	
					     
						   //extension of filename
						   let _filenameextension = _filename.substring(stringindex, _filename.length);
						 
						   //putting it all together
						   _filename = _filenamefront.concat(uuidgeneratornumber, _filenameextension);
					     }
					     else {
					       //if no extension (e.g. ".jpg") is found, add uniqueid, also avoids long filenames
                           if (_filename.length > 64) {
                             let _filenameshort = _filename.slice(0,64);
						     _filename = _filenameshort;
					       }							
					       _filename += uuidgeneratornumber;
					     }	

					     //uses localfile instance					   
					     let localfile = downloadextender.nsilocalfile();
					   
                         localfile.initWithPath(unescape(filter["targetdirectory"])); 
                         //appends name of filename to the targetdirectory (e.g. C:\Videos\ becomes C:\Videos\Test.jpg)
					     localfile.append(_filename); 
					   					   
					     downloadextender.number.increment();
					     let id = downloadextender.number.count;
					   
					   
					     //check for clones of same download
					     let doublet = downloadextender.download.finddoublets(uri);
					   
					   
					     //length has to be greater than 0 and needs to have filename, avoids live streams, cookies, etc. also avoids multiple downloads with same origin
					     if (_length > 0 && _filename != "" && doublet == false) {
                         let download = new downloadextender.download(null, localfile, -1, null, _contenttype, _length, id, uri, null, null);
                         downloadextender.download.addDownload(download);
					   
					     if(downloadextender.pref.autodownload != false) { downloadextender.BrowserOverlay.autodownload(download); }
					   
					     //adds down to download extender main window tree when it's active
					     if (downloadextender.mainwindow != null) { downloadextender.mainwindow.makerow(download); }
					     }
					   }
			         }					  
				  }
                }              			   
		   }
	   }
	   catch (e) { downloadextender.consoleService("observe: "+e); }
	 }, 
	autodownload : function(aDownload) {
	  try { 
	    //persist is needed for creating, listening, etc of download
		let persist = downloadextender.persist();
        //avoids overlapping & problems with cache
		persist.persistFlags = persist.PERSIST_FLAGS_BYPASS_CACHE;		
		//to make URI's from URL & Localfiles
		let ioservice = downloadextender.ioservice();
		//downloadmanager
		let dm = downloadextender.dm();
		//origin
        let obj_URI = ioservice.newURI(aDownload.origin, null, null);
		//target 
        let targetfile = ioservice.newFileURI(aDownload.localfile);	
        let isPrivate = null;
		
		let appinfo = downloadextender.appinfo(); 
		let versionchecker = downloadextender.versioncomparator();
        if (versionchecker.compare(appinfo.version, 20) >=0) {
          //in case of Firefox 20 or later
		  var version20min = true; 
        }
        else {
          //in case of Firefox 19 or below
		  var version20min = false; 
        }
		
        // check if private mode is enabled		
		if (version20min == true) {
		  // Firefox 20+
		  if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
            isPrivate = false;
          }
          else {
            isPrivate = true;
          }
		}
		else {
		  //in case of FF19 and below
		  var inPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIPrivateBrowsingService).privateBrowsingEnabled;
          if (!inPrivateBrowsing) {
            isPrivate = false;
          }
	      else {
	        isPrivate = true;
	      }
		}
		
		//add download to downloadmanager
        let download = dm.addDownload(dm.DOWNLOAD_TYPE_DOWNLOAD, obj_URI, targetfile, '', null, Math.round(Date.now() * 1000), null, persist, isPrivate);
		
		//listener
        downloadListener = function(){
          return {

            init: function(){
			  if (version20min == false) { dm.addListener(this); }
			  else { dm.addPrivacyAwareListener(this);}
            },

            uninit: function(){
			  if (version20min == false) { dm.removeListener(this); }
			  else { dm.removePrivacyAwareListener(this);}
            },

            QueryInterface: function(aIID){
             if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
               aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
               aIID.equals(Components.interfaces.nsISupports))
                return this;
              throw Components.results.NS_NOINTERFACE;
            },

            onSecurityChange : function(prog, req, state, download) { },
            onProgressChange : function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress, download) {

			  //avoid overlapping with other downloads			  
			  if (version20min == false) {
		        if (aDownload.dmid == download.id) {	
                  aDownload.progress = download.percentComplete;
				  aDownload.speed = download.speed;
				  downloadextender.download.updatearray(aDownload);
	            }
			  }
			  else {
			    if (aDownload.dmid == download.guid) {	
                  aDownload.progress = download.percentComplete;
				  aDownload.speed = download.speed;
				  downloadextender.download.updatearray(aDownload);
	            }
			  }
			
		    },
            onStateChange : function(prog, req, flags, status, download) { },
            onDownloadStateChange : function(state, download) {  
			
			  //avoid overlapping with other downloads
			  if (version20min == false) {
			    if (aDownload.dmid == download.id) {	
			    //state is previous state, download.state is current state
			    aDownload.status = download.state;
			    //updates progress to 100% when download is finished
			    if (download.percentComplete == "100") { aDownload.progress = 100; }
                downloadextender.download.updatearray(aDownload);	
                }
              }
              else {
			  	if (aDownload.dmid == download.guid) {	
			    //state is previous state, download.state is current state
			    aDownload.status = download.state;
			    //updates progress to 100% when download is finished
			    if (download.percentComplete == "100") { aDownload.progress = 100; }
                downloadextender.download.updatearray(aDownload);	
                }
              }			  
		    }
       
          };
        };	
        //initializes listener
        let listener = new downloadListener();
		//add listener to download manager	
        if (version20min == false) { dm.addListener(listener); }
		else { dm.addPrivacyAwareListener(listener); }
        persist.progressListener = download;
        let privacyContext = null;		
		//actual download
        persist.saveURI(download.source, null, null, null, null, download.targetFile, privacyContext);
		//assigns download manager (gu)id to download extender download 
		if (version20min == false) { aDownload.dmid = download.id; }
		else {aDownload.dmid = download.guid; }
		
		//update array with specific download
		downloadextender.download.updatearray(aDownload);
	  }
	  catch (e) { downloadextender.consoleService("autodownload: "+e); }
	},
	afterpopuploaded : function(aEvent) {
	  try {	  
	    let listen = downloadextender.pref.listen;
	    document.getElementById("downloadextender-listen-itemmenu").setAttribute("checked", listen);
	    //sets checkbox of toolbar button when present
	    if (document.getElementById("downloadextender-listen-itemtoolbar")) {
	    document.getElementById("downloadextender-listen-itemtoolbar").setAttribute("checked", listen);
	    }
		if (document.getElementById("downloadextender-listen-itemtoolbar2")) {
	    document.getElementById("downloadextender-listen-itemtoolbar2").setAttribute("checked", listen);
	    }
	  }
	  catch (e) { downloadextender.consoleService("afterpopuploaded: "+e); }
    },	
    oncontext : function(aEvent) {
	  try {	
        let parent = aEvent.currentTarget;
        let popup = parent.firstChild;
		aEvent.preventDefault();
		popup.openPopup(parent, "after_start", 0, 0, false, false);
	  }
	  catch (e) { downloadextender.consoleService("oncontext: "+e); }
    },	
    toggledownloadextender : function(aEvent) {

	let mediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);	
	let browser = mediator.getMostRecentWindow("downloadextendermainwindowtype");
	
	try  {
	  //finds out the display type (windows or pullup) TODO tab type
	  if (downloadextender.pref.displaytype == "window") {
        //finds out if the main window of download extender is already active
	    //gives focus if main window is already active
	    if (browser)  {  browser.focus();  }
	    else {
          //opens main window 	  
	      let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
          let win = ww.openWindow(null, "chrome://downloadextender/content/downloadextendermainwindow.xul","downloadextendermainwindow",
	      "chrome=yes,centerscreen,width=800,height=600,resizable,scrollbars", null);
	    }	
	  }
	  else if (downloadextender.pref.displaytype == "pullup") {
	    let browser2 = mediator.getMostRecentWindow("navigator:browser");
        let splitter = browser2.document.getElementById("downloadextenderpullupsplitter");
        let vbox = browser2.document.getElementById("downloadextenderpullupparent");
		if (splitter.collapsed == false && vbox.collapsed == false) {
		  splitter.collapsed = true;
		  vbox.collapsed = true;
		}
		else {
		  splitter.collapsed = false;
		  vbox.collapsed = false;
		}
	  }
	}
	catch (e) { downloadextender.consoleService("toggledownloadextender: "+e); }
  },
    listen : function() {
	  try {
		downloadextender.pref.savelisten(downloadextender.pref.listen);
		if (downloadextender.mainwindow != null) { downloadextender.mainwindow.refreshlistencheckbox(); }
	  }
	  catch (e) { downloadextender.consoleService("listen: "+e); }
  },  
    preferences : function(aEvent) {	
	//modal means the window will not close without user interaction
	//show preferences
	  try {
	    let win = Cc['@mozilla.org/appshell/window-mediator;1'].getService(Ci.nsIWindowMediator).getMostRecentWindow("navigator:browser");  	  
	    win.openDialog("chrome://downloadextender/content/downloadextenderpreferencewindow.xul", "downloadextenderheadersPreferences", "chrome,titlebar,scrollbars,width=1024; height=768,centerscreen,modal,toolbar", this); 
	  }
	  catch (e) { downloadextender.consoleService("preferences: "+e); }
    }
}

window.addEventListener("load", function() {  downloadextender.BrowserOverlay.init();  }, false);
window.addEventListener("unload", function() {  downloadextender.BrowserOverlay.uninit(); }, false);

